# _*_ coding: UTF-8 _*_
# @Time     : 2020/10/15 下午 03:29
# @Author   : Li Jie
# @Site     : http://www.cdtest.cn/
# @File     : function_test.py
# @Software : PyCharm

# 函数
# 执行特定功能的代码块

# 1.函数的定义
def add(a, b):  # def 函数名(形参列表)：
    c = a + b  # 函数体
    return c  # 返回语句,结束函数的调用
    print('return 之后')  # return语句之后的语句不会被执行，是多余的


# 2.函数的调用:通过函数名调用
print(add(1, 99))  # 1,99：实参

print('--------------------------------')


# 饮料机一：
# 只吐出可口可乐
def drink_machine1():
    print('可口可乐')


drink_machine1()


# 饮料机二：
# 选择可乐各类
# 可以吐出可口可乐、芬达、百事可乐
def drink_machine2(drink):
    if drink == '可口可乐':
        print('可口可乐')
    elif drink == '芬达':
        print('芬达')
    else:
        print('百事可乐')


drink_machine2('水')
drink_machine2('可口可乐')

print('-----------------------------------')


# 3函数的参数传递的方式
# 3.1.位置参数：按位置传递
def foo1(a, b):
    print(f'a={a}')
    print(f'b={b}')


foo1(1, 2)
# foo1(1)

print('-----------------------------------')


# 3.2关键字参数：同名传递，根据参数名字传递参数值
def foo2(a, b):
    print(f'a={a}')
    print(f'b={b}')


foo2(b=1, a=2)  # 实参列表中，使用赋值语句，按照参数名字来传递

print('-----------------------------------')


# 3.3 默认值参数
def foo3(a, b=10):
    print(f'a={a}')
    print(f'b={b}')


foo3(1, 2)  # 如果传入参数，优先使用传入的值
foo3(1)  # 如果不传，使用默认值

print('-----------------------------------')


# 3.3 可变参数
def foo4(*foods):
    print('我爱吃的食物有：', end='')
    for food in foods:
        print(food, end=',')
    print()


foo4('火锅')
foo4('火锅', '串串')
foo4('火锅', '串串', '麻辣烫')

foods = ('火锅', '串串', '麻辣烫')
foo4(*foods)
print('-----------------------------------')


def foo5(**address):
    for key, value in address.items():
        print(f'姓名：{key} 电话：{value}')


foo5(张三='13900000001', 李四='13900000002')
address = {'张三': '13900000001', '李四': '13900000002'}
foo5(**address)

print('-----------------------------------')


# 4.局部和全局变量
# 4.1：理解变量的作用域
def foo6():
    num = 6
    print(f'函数内的局部变量num:{num}')


# print(f'函数外无法访问函数内局部变量num:{num}')

# 4.2：global的用法
print('----------------------------------------')
num = 100  # 在定义之后整个py文件都有作用，称为全局变量


def foo7():
    print(f'函数内可以访问全局变量num:{num}')


foo7()
print(f'函数外可以访问全局变量num:{num}')


def foo6():
    global num  # 将变量定义为全局
    num = 66  # 函数内定义的变量称为局部变量，只在函数内有作用
    print(f'函数内访问全局变量num:{num}')


foo6()
print(f'函数外访问全局变量num:{num}')

# 5.函数的返回
# return语句实现函数的返回，结束函数的调用
# 函数必有return语句，如果不写，程序自动添加return None到末尾
print('------------------------------------')


def foo7(a, b):
    c = a + b


print(foo7(1, 2))

print('------------------------------------')


# 匿名函数lambda表达式
def foo8(r):
    area = 3.14 * r * r
    return area


r = 5
print(f'半径为{r}圆面积为:{foo8(r)}')

r = 5
area = lambda r: 3.14 * r * r
print(f'半径为{r}圆面积为:{area(r)}')

print('------------------------------------')


# 函数的递归调用
# 特殊的函数调用方式，函数自己调用自己
# 作用类似于循环，为了实现代码的反复执行
# 思路是：将一个未知或者庞大的问题，逐渐变小，直到有一个确定的答案
# 变量必须越来越小

# 1-100累加：
# 1-100累加=100+99-1累加
# 99-1累加=99+98-1的累加

def foo9(n):  # 必须有形参
    # 必有分支语句
    if n == 1:  # 停止递归
        return 1
    else:  # 将问题逐渐变小
        return n + foo9(n - 1)


print(f'1-100的累加之和为：{foo9(10)}')

# 最大的递归层次
num = 0


def foo10():
    global num
    num += 1
    print(num)
    return foo10()


# foo10()

# 小练习：编写一个函数，必须参数a,b,c11，函数计算a的平方、b的立方、c三者的和，并返回。
print('------------------------------------')


def foo8(a, b, c):
    return a ** 2 + b ** 3 + c


a = foo8(1, 2, 3)
print(a)
